package myJs.user

import argonaut.Argonaut._
import argonaut._
import myJs.Codecs._
import myJs.Implicits._
import myJs.Utils._
import myJs.myPkg.bootstrap.Bootstrap.default._
import myJs.myPkg.jquery._
import myJs.myPkg.{ColumnOptions, PlotlyConfigOptions, TableOptions, myPlotly}
import myJs.tool.Tool
import org.scalajs.dom.ext.Ajax
import scalatags.Text.all._
import shared.Pojo._
import shared.VarTool
import shared.plotly._
import shared.plotly.element.Anchor.Top
import shared.plotly.element.Color.StringColor
import shared.plotly.element.ScatterMode.Lines
import shared.plotly.element._
import shared.plotly.layout.HoverMode.Closest
import shared.plotly.layout.Ref.{Paper, XRef}
import shared.plotly.layout._

import scala.collection.SeqMap
import scala.concurrent.ExecutionContext.Implicits.global
import scala.scalajs.js
import scala.scalajs.js.JSConverters._
import scala.scalajs.js.JSON
import scala.scalajs.js.annotation.{JSExport, JSExportTopLevel}
import scala.scalajs.js.Dynamic.{global => g}

/**
 * Created by yz on 2019/4/25
 */
@JSExportTopLevel("SetBSampleDetail")
object SetBSampleDetail {
  val autoStrId = "autoStr"
  val yStrId = "yStr"
  val tableId="dataTable"

  @JSExport("init")
  def init = {

    Tool.initStrTable

    List(autoStrId,yStrId).foreach{parentId=>
      Tool.initOuterStrTable($(s"#${parentId} #${tableId}"))
    }

  }


  def refreshTableByJson(json: Json, jq: JQuery, f: () => js.Any = () => ()) = {
    val data = Tool.stripNulls(json)
    jq.bootstrapTable("load", data)
    f()
  }

  def fillBasicData(idStr: String) = {
    val url = g.jsRoutes.controllers.SampleController.getBasicData().url.toString
    Ajax.get(url = s"${url}?id=${idStr}").map { xhr =>
      val rs = xhr.responseText.toJArJDS
      rs.head.foreach { case (k, v) =>
        $(s"#sample [id='${k}']").text(v)
      }
    }
  }

  def getStrReadsDatas(rs: String) = {
    rs.decodeOption[List[StrReadsData]].getOrElse(Nil)
  }

  def getSeqDatas(rs: String) = {
    rs.decodeOption[List[CurSeqData]].getOrElse(Nil)
  }

  @JSExport("strDetailShow")
  def strDetailShow(str: String, locus: String) = {
    val seqDatas = getSeqDatas(str)
    val modalId = "locusModal"
    $(".locus").text(locus)
    Tool.refreshTable(JSON.parse(str), $(s"#${modalId} #detailTable"))
    strDetailPlot(seqDatas)
    jQuery(s"#${modalId}").modal("show")
  }

  def statPlot(statDatas: List[StatData]) = {
    val chartId = "statChart"
    val xs = statDatas.map(_.column)
    val as = statDatas.map(_.aCount)
    val ts = statDatas.map(_.tCount)
    val cs = statDatas.map(_.cCount)
    val gs = statDatas.map(_.gCount)
    val ns = statDatas.map(_.nCount)
    case class PlotData(name: String, data: List[String])
    val binWidth = 1
    val plotData = List(PlotData("A", as), PlotData("T", ts), PlotData("C", cs), PlotData("G", gs), PlotData("N", ns)).
      reverse.map { x =>
      val texts = xs.zip(x.data).map { case (xPos, yPos) =>
        s"${x.name}<br>Pos:${xPos}<br>Count:${yPos}"
      }
      Bar(
        x = xs,
        y = x.data,
        marker = Marker(
        ),
        width = binWidth,
        text = texts,
        hoverinfo = HoverInfo.Text,
        name = x.name,
      )
    }

    val tickVals = (1 :: (0 to 400 by 50).toList).map(_.toDouble)
    val layout = Layout(
      title = s"",
      xaxis = Axis(
        title = s"Read Position",
        `type` = AxisType.Linear,
        tickangle = 0.0,
        autorange = true,
        tickfont = Font(size = 10),
        tickvals = tickVals,
        ticktext = tickVals,
      ),
      yaxis = Axis(
        title = s"Number of reads",
        autorange = true
      ),
      margin = Margin(b = 40, l = 60, r = 0, t = 0),
      hovermode = Closest,
      barmode = BarMode.Stack,
      width = 550,
      height = 400,
      dragmode = false
    )
    val config = PlotlyConfigOptions.displayModeBar(false)
    myPlotly.newPlot(chartId, plotData, layout, config)
  }

  def linePlot(statDatas: List[StatData]) = {
    val chartId = "boxPlotChart"
    val xs = statDatas.map(_.column)
    val binWidth = 1
    val q1s = statDatas.map(_.q1)
    val meds = statDatas.map(_.med)
    val means = statDatas.map(_.mean)
    val q3s = statDatas.map(_.q3)
    case class MyData(name: String, data: List[String])
    val plotData = List(MyData("Q1", q1s), MyData("Median", meds), MyData("Mean", means), MyData("Q3", q3s)).reverse.map { x =>
      val texts = xs.zip(x.data).map { case (xPos, yPos) =>
        s"${x.name}<br>Pos:${xPos}<br>Quality:${yPos}"
      }
      Scatter(
        values = xs,
        secondValues = x.data,
        name = x.name,
        marker = Marker(
        ),
        text = texts,
        hoverinfo = HoverInfo.Text,
      )
    }
    val layout = Layout(
      title = s"",
      xaxis = Axis(
        title = s"Read Position",
        `type` = AxisType.Linear,
        tickangle = 0.0,
        autorange = true,
        tickfont = Font(size = 10),
      ),
      yaxis = Axis(
        title = s"Sequencing Qualitiy",
        autorange = true
      ),
      margin = Margin(b = 40, r = 0, t = 0),
      hovermode = Closest,
      width = 550,
      height = 400,
      dragmode = false
    )
    val config = PlotlyConfigOptions.displayModeBar(false)
    myPlotly.newPlot(chartId, plotData, layout, config)
  }

  def boxPlot(statDatas: List[StatData]) = {
    val chartId = "boxPlotChart"
    val xs = statDatas.map(_.column)
    val binWidth = 1
    val q1s = statDatas.map(_.q1)
    val meds = statDatas.map(_.med)
    val means = statDatas.map(_.mean)
    val q3s = statDatas.map(_.q3)
    case class MyData(name: String, data: List[String])
    val plotData = List(MyData("Q1", q1s), MyData("Median", meds), MyData("Mean", means), MyData("Q3", q3s)).reverse.map { x =>
      val texts = xs.zip(x.data).map { case (xPos, yPos) =>
        s"${x.name}<br>Pos:${xPos}<br>Quality:${yPos}"
      }
      Scatter(
        values = xs,
        secondValues = x.data,
        name = x.name,
        marker = Marker(
        ),
        text = texts,
        hoverinfo = HoverInfo.Text,
      )
    }
    val layout = Layout(
      title = s"",
      xaxis = Axis(
        title = s"Read Position",
        `type` = AxisType.Linear,
        tickangle = 0.0,
        autorange = true,
        tickfont = Font(size = 10),
      ),
      yaxis = Axis(
        title = s"Sequencing Qualitiy",
        autorange = true
      ),
      margin = Margin(b = 40, r = 0, t = 0),
      hovermode = Closest,
      width = 550,
      height = 400,
      dragmode = false
    )
    val config = PlotlyConfigOptions.displayModeBar(false)
    myPlotly.newPlot(chartId, plotData, layout, config)
  }

  def strDetailPlot(strSeqDatas: List[CurSeqData]) = {
    val chartId = "strDetailChart"
    val genotypes = strSeqDatas.map(_.genotype).distinct
    val xs = genotypes.indices.toList
    val genotypeXMap = genotypes.zip(xs).toMap
    val step = 0.25
    val plotData = strSeqDatas.map { seqData =>
      val genotype = seqData.genotype
      val index = genotypeXMap(genotype)
      val xMap = Map(index.toDouble -> seqData.reads)
      val xGenotypeMap = Map(index.toDouble -> seqData.genotype)
      val linesX = (BigDecimal(index - 0.5) to BigDecimal(index + 0.5) by BigDecimal(step)).toList.map(_.toDouble)
      val linesY = linesX.map { x =>
        xMap.getOrElse(x, "0")
      }
      val texts = linesX.map { case x =>
        if (xMap.isDefinedAt(x)) {
          val genotype = xGenotypeMap(x)
          val read = xMap(x)
          s"Allele Name:${genotype}<br>Reads:${read}"
        } else ""
      }
      Scatter(
        values = linesX,
        secondValues = linesY,
        marker = Marker(
          color = new StringColor("#1F77B4")
        ),
        hoverinfo = HoverInfo.Text,
        mode = ScatterMode(Lines),
        text = texts,
      )
    }

    val layout = Layout(
      title = s"",
      xaxis = Axis(
        title = s"",
        `type` = AxisType.Linear,
        tickangle = 0.0,
        tickvals = xs,
        ticktext = genotypes,
        autorange = true,
        tickfont = Font(size = 10),
        zeroline = false,
      ),
      yaxis = Axis(
        title = s"Number of reads",
        autorange = true,
      ),
      margin = Margin(b = 20,
        t = 20,
        r = 0),
      width = 400,
      height = 300,
      hovermode = Closest,
      dragmode = false,
      showlegend = false
    )
    val config = PlotlyConfigOptions.displayModeBar(false)
    myPlotly.newPlot(s"${
      chartId
    }", plotData, layout, config)
  }

  def getReadsData(idStr: String) = {
    val url = g.jsRoutes.controllers.SampleController.getReadsData().url.toString
    Ajax.get(url = s"${url}?id=${idStr}").map { xhr =>
      getStrReadsDatas(xhr.responseText)
    }
  }

  def getSampleInfo(idStr: String) = {
    val url = g.jsRoutes.controllers.SampleController.getSampleInfo().url.toString
    Ajax.get(url = s"${url}?id=${idStr}").map { xhr =>
      xhr.responseText.toJDJAn
    }
  }

  def getStatData(idStr: String) = {
    val url = g.jsRoutes.controllers.SampleController.getStatData().url.toString
    Ajax.get(url = s"${url}?id=${idStr}").map { xhr =>
      xhr.responseText.decodeOption[List[StatData]].getOrElse(Nil)
    }
  }

  def getOnlyPanel = {
    g.onlyPanel.toString.toBoolean
  }

  def autoShow(sample: JDJAn, datas: List[StrReadsData]) = {
    val filterDatas = datas.filter(_.kind == "Autosomal").filter { x =>
      if (getOnlyPanel) {
        VarTool.setBAutoSiteNames.contains(x.locus)
      } else true
    }
    Tool.fillReadsData(sample, filterDatas, $(s"#${
      autoStrId
    } #${tableId}"),widthI = 180)
  }

  def yShow(sample: JDJAn, datas: List[StrReadsData]) = {
    val filterDatas = datas.filter(_.kind == "Y").filter { x =>
      if (getOnlyPanel) {
        VarTool.setBYSiteNames.contains(x.locus)
      } else true
    }
    Tool.fillReadsData(sample, filterDatas, $(s"#${
      yStrId
    } #${tableId}"))

  }

  @JSExport("showSampleDetail")
  def showSampleDetail(idStr: String) = {
    $(".id").text(idStr)
    val strF = getSampleInfo(idStr).zip(getReadsData(idStr)).
      map { case (sample, readsDatas) =>
        autoShow(sample, readsDatas)
        yShow(sample, readsDatas)
      }

    fillBasicData(idStr)
      //      .zip(statF)
      .zip(strF).foreach { x =>
    }

  }

}
